home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 1 / CU Amiga Magazine CD-ROM Special Edition (1995)(EMAP Images)(GB)[Issue 1995-11].iso / Aminet / text / tex / EVPaths140.lha / EVPaths.c < prev    next >
C/C++ Source or Header  |  1995-05-05  |  26KB  |  1,214 lines

  1. /*
  2.  * $VER: EVPaths.c 1.40 (03.05.95)
  3.  *
  4.  * Environment Variables Path Routines for TeX related programs.
  5.  *
  6.  * Written by Giuseppe Ghibò
  7.  *
  8.  * Copyright © 1994,1995 by Giuseppe Ghibò <ghibo@galileo.polito.it>
  9.  *
  10. */
  11.  
  12. #include "EVPaths.h"
  13. #include <exec/memory.h>
  14. #include <dos/dosextens.h>
  15. #include <proto/exec.h>
  16. #include <proto/dos.h>
  17. #define USE_BUILTIN_MATH
  18. #include <string.h>
  19.  
  20. #ifdef USE_CFUNC
  21. #include <stdlib.h>
  22. #define AllocMemFunc(a,b) malloc(a)
  23. #define FreeMemFunc(a,b) free(a)
  24. #else
  25. #define AllocMemFunc(a,b) AllocMem(a,b)
  26. #define FreeMemFunc(a,b) FreeMem(a,b)
  27. #endif /* USE_CFUNC */
  28.  
  29. extern struct DosLibrary *DOSBase;
  30.  
  31. #define ENVPATH_OK        0L    /* Success */
  32. #define ENVPATH_NOT_ENOUGH_ROOM    1L    /* Array was truncated */
  33. #define ENVPATH_VAR_NOT_FOUND    2L    /* There is no env var */
  34. #define ENVPATH_NOT_ENOUGH_MEM    3L    /* Not enough mem to alloc */
  35.  
  36. #define ENVPATH_SCAN_NONE    0L    /* No dirs scan */
  37. #define ENVPATH_SCAN_ONE    1L    /* Scan one level subdirs */
  38. #define ENVPATH_SCAN_ALL    2L    /* Scan recursively all subdirs */
  39. #define ENVPATH_SCAN_VAR    3L    /* Scan recursively another var */
  40. #define ENVPATH_SCAN_DEFPATH    4L    /* Put default path */
  41.  
  42. #define ENVPATH_GETVAR        0L    /* Get var */
  43. #define ENVPATH_DONTGETVAR    1L    /* Don't get var */
  44.  
  45. /* Prototypes */
  46. STATIC LONG    __regargs GetVar13(STRPTR name, UBYTE *buf, LONG size);
  47. STATIC VOID     __regargs GetEnvPath(STRPTR envname, UBYTE *buffer, LONG size, STRPTR defpath, LONG mode, LONG *Error);
  48. STATIC STRPTR     __regargs Super_Strtok(STRPTR s, STRPTR p1, STRPTR p2, UBYTE open_delim, UBYTE close_delim);
  49. STATIC LONG    __regargs Add_Path_String(STRPTR s, STRPTR *p, LONG size);
  50. STATIC STRPTR    __regargs Parse_Path_String(STRPTR s, LONG *scan_status);
  51. STATIC LONG    __regargs Scan_Path_String(BPTR dirlock, STRPTR name, BOOL recursion, STRPTR *buf, LONG size);
  52. STATIC VOID    __regargs Insert_Path(struct EnvVarPath *p, APTR path, LONG mode);
  53. STATIC VOID    __regargs Copy_DefPath(struct EnvVarPath *p, APTR defpath, LONG mode);
  54.  
  55. #define PATH_TMPLEN 256
  56. STATIC UBYTE Path_TmpStr[PATH_TMPLEN]; /* temporary storage */
  57.  
  58. /* Super_Strtok() is similar to strtok(). It breaks the string s if
  59.  * one or more chars from the string p1 is matched. The string s is also
  60.  * breaked if one or more chars from the string p2 is matched, but only
  61.  * if such char is found outside the string delimited by
  62.  * open_delim, close_delim. For instance if
  63.  *
  64.  * s = "one,two,three,four,<fi,ve>\nsix,seven" ;
  65.  * p1 = "\n" ;
  66.  * p2 = "," ;
  67.  * open_delim = '<' ;
  68.  * close_delim = '>' ;
  69.  *
  70.  * then after each call to Super_Strtok, we obtain respectively the
  71.  * following strings:
  72.  *
  73.  *    one    two    three    four    <fi,ve>
  74.  *    six    seven
  75.  *
  76.  */
  77. STATIC STRPTR last;
  78.  
  79. STATIC STRPTR __regargs Super_Strtok(STRPTR s, STRPTR p1, STRPTR p2, UBYTE open_delim, UBYTE close_delim)
  80. {
  81.     STRPTR p, s1, s2, token;
  82.     BOOL opened = FALSE;
  83.  
  84.     if (s == NULL && (s = last) == NULL)
  85.         return (NULL);
  86.  
  87.     s += strspn(s, p1);
  88.     s += strspn(s, p2);
  89.  
  90.     if (*s == '\0')
  91.     {
  92.         last = NULL;
  93.         return (NULL);
  94.     }
  95.  
  96.     token = s;
  97.     s1 = s + strcspn(s, p1);
  98.     s2 = s + strcspn(s, p2);
  99.  
  100.     for (p = s; *p && p < s2; p++)
  101.     {
  102.         if (*p == open_delim)
  103.         {
  104.             if (open_delim == close_delim && opened)
  105.                 opened = FALSE;
  106.             else
  107.                 opened = TRUE;
  108.         }
  109.         else
  110.         {
  111.             if (*p == close_delim)
  112.                 opened = FALSE;
  113.         }
  114.     }
  115.  
  116.     if (opened)
  117.     {
  118.         for (p = s2; *p && p < s1 && *p++ != close_delim; ) ;
  119.         s = p;
  120.     }
  121.     else
  122.         s = (s1 < s2 ? s1 : s2);
  123.  
  124.     if (*s == '\0') {
  125.         last = NULL;
  126.     }
  127.     else
  128.     {
  129.         *s = '\0';
  130.         last = s + 1;
  131.     }
  132.  
  133.     return(token);
  134. }
  135.  
  136. /*
  137.  * GetVarLength() returns the length of an environment variable. If the
  138.  * given env var is not found or it doesn't exist, then the returned
  139.  * value is 0L.
  140.  */
  141. LONG __regargs GetVarLength(STRPTR envname)
  142. {
  143.     REGISTER LONG len;
  144.  
  145.     if (DOSBase->dl_lib.lib_Version >= 37)
  146.     {
  147.         UBYTE buffer[1];
  148.  
  149.         if ((len = GetVar(envname, buffer, 1L, GVF_GLOBAL_ONLY | GVF_BINARY_VAR)) != -1L)
  150.             len = IoErr();
  151.         else
  152.             len = 0L;
  153.     }
  154.     else
  155.     {
  156.         struct FileInfoBlock *fib;
  157.         BPTR lock;
  158.  
  159.         SNPrintf(Path_TmpStr, PATH_TMPLEN, "ENV:%s", envname);
  160.  
  161.         if (lock = Lock(Path_TmpStr, ACCESS_READ))
  162.         {
  163.             if ((fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_ANY)))
  164.             {
  165.                 if (Examine(lock, fib))
  166.                 {
  167.                     if (fib->fib_DirEntryType < 0L)
  168.                         len = fib->fib_Size;
  169.                     else
  170.                         len = 0L;
  171.                 }
  172.                 else
  173.                     len = 0L;
  174.  
  175.                 FreeMem(fib, sizeof(struct FileInfoBlock));
  176.             }
  177.             else
  178.                 len = 0L;
  179.  
  180.             UnLock(lock);
  181.         }
  182.         else
  183.             len = 0L;
  184.     }
  185.  
  186.     return (len);
  187. }
  188.  
  189. /*
  190.  * Given an env var name, GetVar13() copies the contents of the env var into
  191.  * the buffer buf. If the size of the env var is greater than the size of
  192.  * the buffer, then the copied length will be size-1.
  193.  * The buffer is terminated with '\0'.
  194.  * The returned value is the number of the bytes copied into the buffer,
  195.  * without consider the trailing '\0'.
  196.  * If the environment variable doesn't exist, no action is performed and
  197.  * the returned value is 0L.
  198.  * Note that this function is similar to the GetVar() function of OS2.1,
  199.  * but has not exactly the same behaviour. In fact GetVar() returns -1L if
  200.  * the var * doesn't exist, while GetVar13() returns 0L in such case.
  201.  */
  202. STATIC LONG __regargs GetVar13(STRPTR name, UBYTE *buf, LONG size)
  203. {
  204.     LONG len;
  205.  
  206.     SNPrintf(Path_TmpStr, PATH_TMPLEN, "ENV:%s", name);
  207.  
  208.     len = min(GetVarLength(name), size);
  209.  
  210.     if (len > 0L)
  211.     {
  212.         BPTR fh;
  213.  
  214.         if ((fh = Open(Path_TmpStr, MODE_OLDFILE)) == DOSFALSE)
  215.             return(0L);
  216.  
  217.         if ((len = Read(fh, buf, len)) > 0L)
  218.         {
  219.             Close(fh);
  220.  
  221.             if (size <= len)
  222.                 len = size - 1L;
  223.  
  224.             buf[len] = '\0';
  225.             return(len);
  226.         }
  227.         else
  228.         {
  229.             Close(fh);
  230.             return(0L);
  231.         }
  232.     }
  233.     else
  234.         return(0L);
  235. }
  236.  
  237. #define ABSTOKEN "\012\014\015" /* breaks only on line feed or form feed or carriage return */
  238. #define RELTOKEN "\t\040,;"
  239. #define LQUOTE '\042'
  240. #define RQUOTE '\042'
  241. #define QUOTE  '\042'
  242.  
  243. /*
  244.  * GetEnvPath() processes the path of a given environment variable. The
  245.  * passed buffer is then filled with path elements. Such buffer may be
  246.  * accessed as an array of string pointers.
  247.  * The 'mode' is either one of EVPATH_DONTGETVAR or EVPATH_GETVAR. If
  248.  * EVPATH_DONTGETVAR is specified then the 'envname' is considered a
  249.  * pointer to a path string, and path elements are treated as they were read
  250.  * from an environment variable.
  251.  *
  252.  * The *Error contains (on exit) one of these values:
  253.  * 
  254.  *  -  ENVPATH_OK: all was successful.
  255.  *
  256.  *  -  ENVPATH_NOT_ENOUGH_ROOM: the buffer is full. In this case the
  257.  *     buffer contains entries which fit into the buffer itself, i.e.
  258.  *     no truncated entries.
  259.  *
  260.  *  -  ENVPATH_VAR_NOT_FOUND: the given environment variable isn't
  261.  *     found or has zero length.
  262.  *
  263.  *  -  ENVPATH_NOT_ENOUGH_MEM: there was a not enough mem during processing.
  264.  *
  265.  */
  266.  
  267. #define MAX_RECURS_VAR 5
  268. STATIC VOID __regargs GetEnvPath(STRPTR envname, UBYTE *buffer, LONG size, STRPTR defpath, LONG mode, LONG *Error)
  269. {
  270.     STRPTR    envbuf, *p = (STRPTR *)buffer, s, tmplast;
  271.     LONG    envbuflen, scan_status = ENVPATH_SCAN_NONE, len;
  272.     STATIC LONG recurs_level = 0L;
  273.     STATIC STRPTR env_names[MAX_RECURS_VAR + 1];
  274.     
  275.     recurs_level++;
  276.  
  277.     if (recurs_level == 1L)
  278.     {
  279.         *Error = ENVPATH_OK;
  280.     }
  281.  
  282.     if (mode == ENVPATH_DONTGETVAR && recurs_level <= 2)
  283.     {
  284.         if (envname)
  285.             envbuf = envname;
  286.         else
  287.         {
  288.             *Error = ENVPATH_VAR_NOT_FOUND;
  289.             --recurs_level;
  290.             return;
  291.         }
  292.     }
  293.     else
  294.     {
  295.         envbuflen = GetVarLength(envname) + 1L;
  296.  
  297.         if (envbuflen <= 1L)
  298.         {
  299.             *Error = ENVPATH_VAR_NOT_FOUND;
  300.             --recurs_level;
  301.             return;
  302.         }
  303.  
  304.         if (envbuf = AllocMem(envbuflen, MEMF_ANY | MEMF_CLEAR))
  305.         {
  306.             if (DOSBase->dl_lib.lib_Version >= 37)
  307.                 GetVar(envname, envbuf, envbuflen, GVF_GLOBAL_ONLY | GVF_BINARY_VAR);
  308.             else
  309.                 GetVar13(envname, envbuf, envbuflen);
  310.         }
  311.         else
  312.         {
  313.             *Error = ENVPATH_NOT_ENOUGH_MEM;
  314.             --recurs_level;
  315.             return;
  316.         }
  317.  
  318.         len = strlen(envname) + 1L;
  319.  
  320.         if (env_names[recurs_level - 1] = AllocMem(len, MEMF_ANY))
  321.         {
  322.             strcpy(env_names[recurs_level - 1], envname); /* store env name to avoid recursion loops */
  323.             env_names[recurs_level] = NULL;
  324.         }
  325.         else
  326.         {
  327.             *Error = ENVPATH_NOT_ENOUGH_MEM;
  328.             --recurs_level;
  329.             return;
  330.         }
  331.     }
  332.  
  333.     s = Super_Strtok(envbuf, ABSTOKEN, RELTOKEN, LQUOTE, RQUOTE); /* get first token */
  334.  
  335.     do
  336.     {
  337.         s = Parse_Path_String(s, &scan_status);
  338.  
  339.         if (scan_status == ENVPATH_SCAN_VAR)
  340.         {
  341.             if (recurs_level < MAX_RECURS_VAR)
  342.             {
  343.                 BOOL recursion = TRUE;
  344.                 LONG i = 0L;
  345.  
  346.                 while (env_names[i])
  347.                 {
  348.                     if (!stricmp(env_names[i++], s))
  349.                     {
  350.                         recursion = FALSE;
  351.                         break;
  352.                     }
  353.                 }
  354.  
  355.                 if (recursion)
  356.                 {
  357.                     tmplast = last; /* save last pos for Super_Strtok() */
  358.                     GetEnvPath(s, buffer, size, NULL, ENVPATH_GETVAR, Error);
  359.                     last = tmplast; /* restore last pos for Super_Strtok() */
  360.  
  361.                     if (*Error == ENVPATH_VAR_NOT_FOUND)
  362.                         *Error = ENVPATH_OK; /* ignore recurs vars not found */
  363.                 }
  364.             }
  365.         }
  366.         else if (scan_status == ENVPATH_SCAN_ONE || scan_status == ENVPATH_SCAN_ALL)
  367.         {
  368.             BPTR dirlock;
  369.  
  370.             if (dirlock = Lock(s, ACCESS_READ))
  371.             {
  372.                 *Error = Add_Path_String(s, p, size);
  373.  
  374.                 if (*Error == ENVPATH_OK)
  375.                     *Error = Scan_Path_String(dirlock, s, (scan_status == ENVPATH_SCAN_ALL ? TRUE : FALSE), p, size);
  376.  
  377.                 UnLock(dirlock);
  378.             }
  379.         }
  380.         else if (scan_status == ENVPATH_SCAN_DEFPATH)
  381.         {
  382.             if (defpath && *defpath)
  383.             {
  384.                 tmplast = last;    /* save last pos for Super_Strtok() */
  385.                 GetEnvPath(defpath, buffer, size, NULL, ENVPATH_DONTGETVAR, Error);
  386.                 last = tmplast; /* restore last pos for Super_Strtok() */
  387.             }
  388.         }
  389.         else
  390.             *Error = Add_Path_String(s, p, size);
  391.     }
  392.     while (*Error == ENVPATH_OK && (s = Super_Strtok(NULL, ABSTOKEN, RELTOKEN, LQUOTE, RQUOTE)));
  393.  
  394.     if (mode != ENVPATH_DONTGETVAR)
  395.         FreeMem(env_names[recurs_level - 1], len);
  396.  
  397.     if (envbuf && mode != ENVPATH_DONTGETVAR)
  398.         FreeMem(envbuf, envbuflen);
  399.  
  400.     --recurs_level;
  401. }
  402.  
  403. /*
  404.  * Add_Path_String(). Adds the string s to the array of strings p.
  405.  * The array must be initialized before to be passed to this function: the
  406.  * first element must be NULL! (p[0] = NULL).
  407.  *
  408.  * Returned values: ENVPATH_OK or ENVPATH_NOT_ENOUGH_ROOM.
  409.  *
  410.  */
  411. STATIC LONG __regargs Add_Path_String(STRPTR s, STRPTR *p, LONG size)
  412. {
  413.     LONG i = 0L, len;
  414.     STRPTR q;
  415.  
  416.     if (size < (2 * sizeof(STRPTR) + 1L))
  417.         return (ENVPATH_NOT_ENOUGH_ROOM);
  418.  
  419.     len = strlen(s);
  420.  
  421.     if (p[0] == NULL)
  422.     {
  423.         q = (STRPTR)p + size - (len + 1L);
  424.     }
  425.     else
  426.     {
  427.         for (i = 0L; p[i]; i++);
  428.         q = p[i-1] - (len + 1L);
  429.     }
  430.  
  431.     if (&p[i] > (STRPTR *)(q - 2*sizeof(STRPTR)))
  432.     {
  433.         p[i] = NULL;
  434.         return (ENVPATH_NOT_ENOUGH_ROOM);
  435.     }
  436.     else
  437.     {
  438.         LONG j;
  439.         BOOL is_valid_entry = TRUE;
  440.  
  441.         for (j = 0L; j < i; j++)
  442.         {
  443.             if (!stricmp(p[j], s))
  444.             {
  445.                 is_valid_entry = FALSE;
  446.             }
  447.         }
  448.  
  449.         if (is_valid_entry)
  450.         {
  451.             p[i] = q;
  452.             strcpy(p[i], s);
  453.             p[i+1] = NULL;
  454.         }
  455.     }
  456.  
  457.     return (ENVPATH_OK);
  458. }
  459.  
  460. #define MAX_RECURS_DIR 10L    /* maximum recursion dir level */
  461. STATIC LONG __regargs Scan_Path_String(BPTR dirlock, STRPTR name, BOOL recursion, STRPTR *buf, LONG size)
  462. {
  463.     struct FileInfoBlock *fib;
  464.     LONG result = ENVPATH_OK;
  465.     STATIC LONG recurs_level = 0L;
  466.  
  467.     recurs_level++;
  468.  
  469.     if ((fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_ANY)))
  470.     {
  471.         if (Examine(dirlock, fib))
  472.         {
  473.             if (fib->fib_DirEntryType > 0L)
  474.             {
  475.                 while (ExNext(dirlock, fib) && (result == ENVPATH_OK))
  476.                 {
  477.                     if (fib->fib_DirEntryType > 0L)
  478.                     {
  479.                         LONG len = strlen(name);
  480.  
  481.                         if (len-- > 0L)
  482.                         {
  483.                             SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s%s%s", name,
  484.                                  ((name[len] != '/') && (name[len] != ':') ? "/" : ""), fib->fib_FileName);
  485.                         }
  486.                         else
  487.                         {
  488.                             if (fib->fib_FileName)
  489.                                 SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", fib->fib_FileName);
  490.                         }
  491.  
  492.                         result = Add_Path_String(Path_TmpStr, buf, size);
  493.  
  494.                         if (recursion && (result == ENVPATH_OK) && (recurs_level < MAX_RECURS_DIR))
  495.                         {
  496.                             BPTR OldDirLock, NewDirLock;
  497.  
  498.                             OldDirLock = CurrentDir(dirlock);
  499.  
  500.                             if (NewDirLock = Lock(fib->fib_FileName, ACCESS_READ))
  501.                             {
  502.                                 STRPTR dirname;
  503.  
  504.                                 len = strlen(Path_TmpStr) + 1L;
  505.  
  506.                                 if (dirname = AllocMem(len, MEMF_ANY))
  507.                                 {
  508.                                     strcpy(dirname, Path_TmpStr);
  509.                                     result = Scan_Path_String(NewDirLock, dirname, recursion, buf, size);
  510.                                     FreeMem(dirname, len);
  511.                                 }
  512.                                 UnLock(NewDirLock);
  513.                             }
  514.                             CurrentDir(OldDirLock);
  515.                         }
  516.                     }
  517.                 }
  518.             }
  519.         }
  520.         FreeMem(fib, sizeof(struct FileInfoBlock));
  521.     }
  522.     else
  523.         result = ENVPATH_NOT_ENOUGH_MEM;
  524.  
  525.     --recurs_level;
  526.     return (result);
  527. }
  528.  
  529.  
  530. STATIC STRPTR __regargs Parse_Path_String(STRPTR s, LONG *scan_status)
  531. {
  532.     UBYTE *r, *t;
  533.     LONG len;
  534.  
  535.     *scan_status = ENVPATH_SCAN_NONE;
  536.  
  537.     if (!s || !*s)
  538.         return("");
  539.  
  540.     if (*s == LQUOTE)
  541.     {
  542.         for (t = ++s; *t; t++);    /* remove leading quote and seek to the end of the string */
  543.  
  544.         if (*--t == RQUOTE)
  545.             *t = '\0';    /* remove trailing quote */
  546.     }
  547.  
  548.     if (s[0] == '.')    /* '.' or './' represents current dir */
  549.     {
  550.         switch (s[1])
  551.         {
  552.             case '\0':
  553.                 s[0] = '\0';    /* null string is current dir */
  554.                 break;
  555.  
  556.             case '/':
  557.                 s += 2;
  558.                 break;
  559.         }
  560.  
  561.         r = t = s;
  562.  
  563.         while (*t)    /* '..' or '../' is also parent dir */
  564.         {
  565.             if (t[0] == '.' && t[1] == '.')
  566.             {
  567.                 if (t[2] == '/')
  568.                     t += 2;
  569.                 else if (t[2] == '\0')
  570.                 {
  571.                     *r++ = '/';
  572.                     break;
  573.                 }
  574.             }
  575.             *r++ = *t++;
  576.         }
  577.         *r = '\0';
  578.     }
  579.  
  580.     len = strlen(s);
  581.  
  582.     if (len > 0)
  583.     {
  584.         if (s[0] == '$')
  585.         {
  586.             s++;
  587.             *scan_status = ENVPATH_SCAN_VAR;
  588.             if (s[0] == QUOTE)
  589.                 s++;
  590.         }
  591.         else if (s[0] == '?' && s[1] == '\0')
  592.         {
  593.             s++;
  594.             *scan_status = ENVPATH_SCAN_DEFPATH;
  595.         }
  596.         else
  597.         {
  598.             switch (s[len - 1])
  599.             {
  600.                 case '*':
  601.                     if (len > 1)
  602.                     {
  603.                         switch (s[len - 2])
  604.                         {
  605.                             case '*':
  606.                                 *scan_status = ENVPATH_SCAN_ALL;
  607.                                 s[len - 2] = '\0';
  608.                                 break;
  609.  
  610.                             default:
  611.                                 *scan_status = ENVPATH_SCAN_ONE;
  612.                                 s[len - 1] = '\0';
  613.                                 break;
  614.                         }
  615.                     }
  616.                     else /* len == 1 */
  617.                     {
  618.                         *scan_status = ENVPATH_SCAN_ONE;
  619.                         s[len - 1] = '\0';
  620.                     }
  621.  
  622.                     break;
  623.  
  624.                 case '?':
  625.                     if (len > 1)
  626.                     {
  627.                         switch (s[len - 2])
  628.                         {
  629.                             case '#':
  630.                                 *scan_status = ENVPATH_SCAN_ONE;
  631.                                 s[len - 2] = '\0';
  632.                                 break;
  633.  
  634.                             default:
  635.                                 *scan_status = ENVPATH_SCAN_NONE;
  636.                                 break;
  637.                         }
  638.                     }
  639.                     else
  640.                         *scan_status = ENVPATH_SCAN_NONE;
  641.  
  642.                     break;
  643.  
  644.                 case '>':
  645.                     if (len > 1)
  646.                     {
  647.                         switch (s[len - 2])
  648.                         {
  649.                             case '*':
  650.                                 *scan_status = ENVPATH_SCAN_ALL;
  651.                                 s[len - 2] = '\0';
  652.                                 break;
  653.  
  654.                             case '?':
  655.                                 if (len > 2)
  656.                                 {
  657.                                     switch (s[len - 3])
  658.                                     {
  659.                                         case '#':
  660.                                             *scan_status = ENVPATH_SCAN_ALL;
  661.                                             s[len -3] = '\0';
  662.                                             break;
  663.  
  664.                                         default:
  665.                                             *scan_status = ENVPATH_SCAN_NONE;
  666.                                             break;
  667.                                     }
  668.                                 }
  669.                                 else
  670.                                     *scan_status = ENVPATH_SCAN_NONE;
  671.  
  672.                                 break;
  673.  
  674.                             default:
  675.                                 *scan_status = ENVPATH_SCAN_NONE;
  676.                                 break;
  677.                         }
  678.                     }
  679.                     else
  680.                         *scan_status = ENVPATH_SCAN_NONE;
  681.  
  682.                     break;
  683.  
  684.                 default:
  685.                     *scan_status = ENVPATH_SCAN_NONE;
  686.                     break;
  687.             }
  688.         }
  689.     }
  690.  
  691.     return(s);
  692. }
  693.  
  694. /*
  695.  * Alloc_EnvVarPath(). Alloc an EnvVarPath structure.
  696.  *
  697.  */
  698. struct EnvVarPath __regargs *Alloc_EnvVarPath(STRPTR varname, LONG size)
  699. {
  700.     struct EnvVarPath *p;
  701.  
  702.     if (p = AllocMemFunc(sizeof(struct EnvVarPath), MEMF_ANY))
  703.     {
  704.         if ((size >= 2*sizeof(STRPTR) + 1L) && (p->storage.buffer = AllocMemFunc(size, MEMF_ANY)))
  705.         {
  706.             if (p->name = AllocMemFunc(strlen(varname) + 1, MEMF_ANY))
  707.             {
  708.                 strcpy(p->name, varname);
  709.                 p->storage.strings[0] = NULL; /* init first entry */
  710.                 p->size = size;
  711.                 p->status = ENVPATH_BUFFER_EMPTY;
  712.                 p->defpath = NULL;
  713.                 p->pos = 0L;
  714.             }
  715.             else
  716.             {
  717.                 FreeMemFunc(p->storage.buffer, size);
  718.                 FreeMemFunc(p, sizeof(struct EnvVarPath));
  719.                 p = NULL;
  720.             }
  721.         }
  722.         else
  723.         {
  724.             FreeMemFunc(p, sizeof(struct EnvVarPath));
  725.             p = NULL;
  726.         }
  727.     }
  728.  
  729.     return(p);
  730. }
  731.  
  732. /*
  733.  * Free_EnvVarPath. Frees an allocated EnvVarPath structure.
  734.  *
  735.  */
  736. VOID __regargs Free_EnvVarPath(struct EnvVarPath *p)
  737. {
  738.     if (p)
  739.     {
  740.         FreeMemFunc(p->name, strlen(p->name) + 1);
  741.  
  742.         if (p->storage.buffer)
  743.             FreeMemFunc(p->storage.buffer, p->size);
  744.  
  745.         if (p->defpath)
  746.             FreeMemFunc(p->defpath, strlen(p->defpath) + 1);
  747.  
  748.         FreeMemFunc(p, sizeof(struct EnvVarPath));
  749.     }
  750. }
  751.  
  752. /*
  753.  * Init_EnvVarPath() inits an EnvVarPath structure provided by
  754.  * Alloc_EnvVarPath().
  755.  *
  756.  * defpath is an array of string pointers or a string pointer to be used
  757.  * if the specified environment variable doesn't exists or has zero length.
  758.  * 'mode' is one of ENVPATH_DEFSTR or ENPATH_DEFARR. If it is ENVPATH_DEFSTR
  759.  * then defpath is considered a string pointer, otherwise ENVPATH_DEFARR
  760.  * specifies that defpath is an array of string pointers.
  761.  *
  762.  */
  763. VOID __regargs Init_EnvVarPath(struct EnvVarPath *p, APTR defpath, LONG mode)
  764. {
  765.     if (p)
  766.     {
  767.         LONG Error;
  768.  
  769.         if ((mode & ENVPATH_CURRENTDIR_FIRST) == ENVPATH_CURRENTDIR_FIRST)
  770.             Insert_Path(p, ".", ENVPATH_DEFSTR);
  771.  
  772.         if ((mode & ENVPATH_PREPEND_PATH) == ENVPATH_PREPEND_PATH)
  773.         {
  774.             Insert_Path(p, defpath, mode);
  775.             GetEnvPath(p->name, p->storage.buffer, p->size, NULL, ENVPATH_GETVAR, &Error);
  776.         }
  777.         else if ((mode & ENVPATH_APPEND_PATH) == ENVPATH_APPEND_PATH)
  778.         {
  779.             GetEnvPath(p->name, p->storage.buffer, p->size, NULL, ENVPATH_GETVAR, &Error);
  780.             Insert_Path(p, defpath, mode);
  781.         }
  782.         else
  783.         {
  784.             Copy_DefPath(p, defpath, mode);
  785.             GetEnvPath(p->name, p->storage.buffer, p->size, p->defpath, ENVPATH_GETVAR, &Error);
  786.         }
  787.  
  788.         switch (Error)
  789.         {
  790.             case ENVPATH_OK:
  791.                 p->status = ENVPATH_BUFFER_COMPLETE;
  792.                 break;
  793.  
  794.             case ENVPATH_NOT_ENOUGH_ROOM:
  795.                 p->status = ENVPATH_BUFFER_FULL;
  796.                 break;
  797.  
  798.             case ENVPATH_NOT_ENOUGH_MEM:
  799.                 p->status = ENVPATH_BUFFER_TRUNC;
  800.                 break;
  801.  
  802.             case ENVPATH_VAR_NOT_FOUND:
  803.                 if (!(mode & (ENVPATH_PREPEND_PATH | ENVPATH_APPEND_PATH)))
  804.                     Insert_Path(p, defpath, mode);
  805.                 break;
  806.  
  807.             default:
  808.                 p->status = ENVPATH_BUFFER_EMPTY;
  809.                 break;
  810.         }
  811.     }
  812. }
  813.  
  814.  
  815. /*
  816.  * Copy the default path to the field `defpath' of the structure EnvVarPath.
  817.  */
  818. STATIC VOID __regargs Copy_DefPath(struct EnvVarPath *p, STRPTR defpath, LONG mode)
  819. {
  820.     if (defpath && *defpath)
  821.     {
  822.         STRPTR defbuf;
  823.         LONG l = 0L;
  824.  
  825.         if ((mode & ENVPATH_DEFARR) == ENVPATH_DEFARR)
  826.         {
  827.             LONG i = 0L;
  828.             STRPTR *array = (STRPTR *) defpath, s;
  829.  
  830.             while (array[i])
  831.                 l += strlen(array[i++]) + 1L;
  832.  
  833.             if (defbuf = AllocMemFunc(++l, MEMF_ANY))
  834.             {
  835.                 s = defbuf;
  836.                 *s = '\0';
  837.                 i = 0L;
  838.  
  839.                 while (array[i])
  840.                 {
  841.                     strcat(s, array[i++]);
  842.                     strcat(s, " ");
  843.                 }
  844.  
  845.                 p->defpath = defbuf;
  846.             }
  847.             else
  848.                 p->defpath = NULL;
  849.         }
  850.         else
  851.         {
  852.             l = strlen(defpath) + 1L;
  853.  
  854.             if (defbuf = AllocMemFunc(l, MEMF_ANY))
  855.             {
  856.                 memcpy(defbuf, defpath, l);
  857.                 p->defpath = defbuf;
  858.             }
  859.             else
  860.                 p->defpath = NULL;
  861.         }
  862.     }
  863. }
  864.  
  865. /*
  866.  * Insert_Path() adds a path to p->storage.buffer; mode is one of
  867.  * ENVPATH_DEFARR or ENVPATH_DEFSTR, same as in the function
  868.  * Init_EnvVarPath().
  869.  */
  870. STATIC VOID __regargs Insert_Path(struct EnvVarPath *p, APTR path, LONG mode)
  871. {
  872.     LONG Error = ENVPATH_OK;
  873.  
  874.     if (path)
  875.     {
  876.         if ((mode & ENVPATH_DEFARR) == ENVPATH_DEFARR)
  877.         {
  878.             LONG i = 0L, l = 0L;
  879.             STRPTR *array = (STRPTR *) path, BufTmp, s;
  880.  
  881.             while (array[i])
  882.                 l += strlen(array[i++]) + 1L;
  883.  
  884.             if (BufTmp = AllocMem(++l, MEMF_ANY))
  885.             {
  886.                 s = BufTmp;
  887.                 *s = '\0';
  888.                 i = 0L;
  889.  
  890.                 while (array[i])
  891.                 {
  892.                     strcat(s, array[i++]);
  893.                     strcat(s, " ");
  894.                 }
  895.  
  896.                 GetEnvPath(BufTmp, p->storage.buffer, p->size, NULL, ENVPATH_DONTGETVAR, &Error);
  897.                 FreeMem(BufTmp, l);
  898.             }
  899.             else
  900.                 Error = ENVPATH_NOT_ENOUGH_MEM;
  901.         }
  902.         else
  903.             GetEnvPath(path, p->storage.buffer, p->size, NULL, ENVPATH_DONTGETVAR, &Error);
  904.  
  905.         switch(Error)
  906.         {
  907.             case ENVPATH_OK:
  908.                 p->status = ENVPATH_BUFFER_COMPLETE;
  909.                 break;
  910.  
  911.             case ENVPATH_NOT_ENOUGH_ROOM:
  912.                 p->status = ENVPATH_BUFFER_FULL;
  913.                 break;
  914.  
  915.             case ENVPATH_NOT_ENOUGH_MEM:
  916.                 p->status = ENVPATH_BUFFER_TRUNC;
  917.                 break;
  918.  
  919.             case ENVPATH_VAR_NOT_FOUND:
  920.                 p->status = ENVPATH_BUFFER_EMPTY;
  921.                 break;
  922.  
  923.             default:
  924.                 p->status = ENVPATH_BUFFER_EMPTY;
  925.                 break;
  926.         }
  927.     }
  928.     else
  929.         p->status = ENVPATH_BUFFER_EMPTY;
  930. }
  931.  
  932. /*
  933.  * Given a pointer to an initialized structure EnvVarPath, a filename
  934.  * and a buffer, EVP_FileSearch() returns the string pointer to the
  935.  * complete filename found. The returned string pointer is same of buffer.
  936.  * If the file isn't found then NULL will be returned and buffer will
  937.  * contains the empty string ("").
  938.  *
  939.  */
  940. STRPTR __regargs
  941. EVP_FileSearch(STRPTR filename, struct EnvVarPath *evp, UBYTE *buffer, LONG size)
  942. {
  943.     LONG i = 0L, len ;
  944.  
  945.     if (evp && buffer && size > 0L && filename && *filename)
  946.     {
  947.         *buffer = '\0';
  948.  
  949.         while (evp->storage.strings[i])
  950.         {
  951.             BPTR fh, lock;
  952.  
  953.             if (DOSBase->dl_lib.lib_Version >= 37)
  954.             {
  955.                 SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", evp->storage.strings[i]);
  956.                 AddPart(Path_TmpStr, filename, PATH_TMPLEN);
  957.                 len = strlen(Path_TmpStr);
  958.             }
  959.             else
  960.             {
  961.                 LONG l = strlen(evp->storage.strings[i]);
  962.  
  963.                 if (l > 0L && !strchr(filename, ':'))
  964.                 {
  965.                     UBYTE c = evp->storage.strings[i][l - 1];
  966.  
  967.                     len = SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s%s%s", evp->storage.strings[i],
  968.                         ((c != '/' && c != ':') ? "/" : ""), filename);
  969.                 }
  970.                 else
  971.                     len = SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", filename);
  972.             }
  973.  
  974.             if (Path_TmpStr[0] && (lock = Lock(Path_TmpStr, ACCESS_READ)) != DOSFALSE)
  975.             {
  976.                 if (DOSBase->dl_lib.lib_Version >= 37)
  977.                 {
  978.                     if ((fh = OpenFromLock(lock)) != DOSFALSE)
  979.                     {
  980.                         Close(fh);
  981.                         memcpy(buffer, Path_TmpStr, min(len, size));
  982.                         buffer[min(len, size - 1)] = '\0';
  983.                     }
  984.                     else /* probable lock on directory here */
  985.                     {
  986.                         UnLock(lock);
  987.                     }
  988.                 }
  989.                 else
  990.                 {
  991.                     UnLock(lock);
  992.  
  993.                     if ((fh = Open(Path_TmpStr, MODE_OLDFILE)) != DOSFALSE)
  994.                     {
  995.                         Close(fh);
  996.                         memcpy(buffer, Path_TmpStr, min(len, size));
  997.                         buffer[min(len, size - 1)] = '\0';
  998.                     }
  999.                 }
  1000.             }
  1001.  
  1002.             if (*buffer)
  1003.                 break;
  1004.             else
  1005.                 i++;
  1006.         }
  1007.     }
  1008.     else
  1009.     {
  1010.         if (size > 0L)
  1011.             buffer[0] = '\0';
  1012.     }
  1013.  
  1014.     if (*buffer)
  1015.         return(buffer);
  1016.     else
  1017.         return(NULL);
  1018. }
  1019.  
  1020. #ifndef USE_CFUNC
  1021. /*
  1022.  * EVP_Open() is similar to the DOS function Open(), but uses the
  1023.  * path provided with the structure evp. `mode' is same in the original
  1024.  * Open() function (e.g. MODE_OLDFILE or MODE_NEWFILE).
  1025.  * If we want to know the full name of the opened file we have to provide
  1026.  * a buffer and its size, otherwise simply pass NULL for such arguments.
  1027.  *
  1028. */
  1029. BPTR __regargs
  1030. EVP_Open(STRPTR filename, struct EnvVarPath *evp, UBYTE *buffer, LONG size, LONG mode)
  1031. {
  1032.     LONG i = 0L, len;
  1033.     BPTR fh = DOSFALSE, lock;
  1034.     BOOL uselock;
  1035.  
  1036.     if (evp && filename && *filename)
  1037.     {
  1038.         if (buffer && size > 0L)
  1039.             *buffer = '\0';
  1040.  
  1041.         if (mode == MODE_OLDFILE || mode == MODE_READWRITE)
  1042.             uselock = TRUE;
  1043.         else
  1044.             uselock = FALSE;
  1045.  
  1046.         while (evp->storage.strings[i])
  1047.         {
  1048.             if (DOSBase->dl_lib.lib_Version >= 37)
  1049.             {
  1050.                 SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", evp->storage.strings[i]);
  1051.                 AddPart(Path_TmpStr, filename, PATH_TMPLEN);
  1052.                 len = strlen(Path_TmpStr);
  1053.             }
  1054.             else
  1055.             {
  1056.                 LONG l = strlen(evp->storage.strings[i]);
  1057.  
  1058.                 if (l > 0L && !strchr(filename, ':'))
  1059.                 {
  1060.                     UBYTE c = evp->storage.strings[i][l - 1];
  1061.  
  1062.                     len = SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s%s%s", evp->storage.strings[i],
  1063.                         ((c != '/' && c != ':') ? "/" : ""), filename);
  1064.                 }
  1065.                 else
  1066.                     len = SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", filename);
  1067.             }
  1068.  
  1069.             if (uselock)
  1070.             {
  1071.                 if (Path_TmpStr[0] && (lock = Lock(Path_TmpStr, ACCESS_READ)) != DOSFALSE)
  1072.                 {
  1073.                     if (DOSBase->dl_lib.lib_Version >= 37)
  1074.                     {
  1075.                         if ((fh = OpenFromLock(lock)) != DOSFALSE)
  1076.                         {
  1077.                             if (buffer && size > 0L)
  1078.                             {
  1079.                                 memcpy(buffer, Path_TmpStr, min(len, size));
  1080.                                 buffer[min(len, size - 1)] = '\0';
  1081.                             }
  1082.                             break;
  1083.                         }
  1084.                     }
  1085.                     else
  1086.                     {
  1087.                         UnLock(lock);
  1088.                         if ((fh = Open(Path_TmpStr, mode)) != DOSFALSE)
  1089.                         {
  1090.                             if (buffer && size > 0L)
  1091.                             {
  1092.                                 memcpy(buffer, Path_TmpStr, min(len, size));
  1093.                                 buffer[min(len, size - 1)] = '\0';
  1094.                             }
  1095.                             break;
  1096.                         }
  1097.                     }
  1098.                 }
  1099.             }
  1100.             else
  1101.             {
  1102.                 if (Path_TmpStr[0] && (fh = Open(Path_TmpStr, mode)) != DOSFALSE)
  1103.                 {
  1104.                     if (buffer && size > 0L)
  1105.                     {
  1106.                         memcpy(buffer, Path_TmpStr, min(len, size));
  1107.                         buffer[min(len, size - 1)] = '\0';
  1108.                     }
  1109.                     break;
  1110.                 }
  1111.             }
  1112.             i++;
  1113.         }
  1114.     }
  1115.     else
  1116.     {
  1117.         if (buffer && size > 0L)
  1118.             buffer[0] = '\0';
  1119.     }
  1120.  
  1121.     return(fh);
  1122. }
  1123. #else /* USE_CFUNC */
  1124. /*
  1125.  * EVP_fopen() is similar to the C function fopen(), but uses the
  1126.  * path provided with the structure evp. `mode' is same in the original
  1127.  * fopen() function (e.g. "r" or "w").
  1128.  * If we want to know the full name of the opened file we have to provide
  1129.  * a buffer and its size, otherwise simply pass NULL for such arguments.
  1130.  *
  1131. */
  1132. FILE * __regargs
  1133. EVP_fopen(STRPTR filename, struct EnvVarPath *evp, UBYTE *buffer, LONG size, char *mode)
  1134. {
  1135.     LONG i = 0L, len;
  1136.     FILE *fh = NULL;
  1137.     BPTR lock;
  1138.     BOOL uselock;
  1139.  
  1140.     if (evp && filename && *filename)
  1141.     {
  1142.         if (buffer && size > 0L)
  1143.             *buffer = '\0';
  1144.  
  1145.         if (!strcmp(mode,"r") || !strcmp(mode,"rb") || !strcmp(mode,"rw"))
  1146.             uselock = TRUE;
  1147.         else
  1148.             uselock = FALSE;
  1149.  
  1150.         while (evp->storage.strings[i])
  1151.         {
  1152.             if (DOSBase->dl_lib.lib_Version >= 37)
  1153.             {
  1154.                 SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", evp->storage.strings[i]);
  1155.                 AddPart(Path_TmpStr, filename, PATH_TMPLEN);
  1156.                 len = strlen(Path_TmpStr);
  1157.             }
  1158.             else
  1159.             {
  1160.                 LONG l = strlen(evp->storage.strings[i]);
  1161.  
  1162.                 if (l > 0L && !strchr(filename, ':'))
  1163.                 {
  1164.                     UBYTE c = evp->storage.strings[i][l - 1];
  1165.  
  1166.                     len = SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s%s%s", evp->storage.strings[i],
  1167.                         ((c != '/' && c != ':') ? "/" : ""), filename);
  1168.                 }
  1169.                 else
  1170.                     len = SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", filename);
  1171.             }
  1172.  
  1173.             if (uselock)
  1174.             {
  1175.                 if (Path_TmpStr[0] && (lock = Lock(Path_TmpStr, ACCESS_READ)) != DOSFALSE)
  1176.                 {
  1177.                     UnLock(lock);
  1178.  
  1179.                     if (fh = fopen(Path_TmpStr, mode))
  1180.                     {
  1181.                         if (buffer && size > 0L)
  1182.                         {
  1183.                             memcpy(buffer, Path_TmpStr, min(len, size));
  1184.                             buffer[min(len, size - 1)] = '\0';
  1185.                         }
  1186.                         break;
  1187.                     }
  1188.                 }
  1189.             }
  1190.             else
  1191.             {
  1192.                 if (Path_TmpStr[0] && (fh = fopen(Path_TmpStr, mode)) != NULL)
  1193.                 {
  1194.                     if (buffer && size > 0L)
  1195.                     {
  1196.                         memcpy(buffer, Path_TmpStr, min(len, size));
  1197.                         buffer[min(len, size - 1)] = '\0';
  1198.                     }
  1199.                     break;
  1200.                 }
  1201.             }
  1202.             i++;
  1203.         }
  1204.     }
  1205.     else
  1206.     {
  1207.         if (buffer && size > 0L)
  1208.             buffer[0] = '\0';
  1209.     }
  1210.  
  1211.     return(fh);
  1212. }
  1213. #endif /* USE_CFUNC */
  1214.